package com.uw.uwregistry.cluster;

import com.uw.uwregistry.meta.ServerMeta;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * 注册中心选主
 */
@Slf4j
public class Election {


    /**
     * 方案一：各个节点根据相同算法选主，保障每个节点有一致的信息，选主结果一致。 => 参考 uw-registry 实现
     * 方案二：外部有一个分布式锁，谁拿到锁谁是主。 => 参考 uw-config 实现
     * 方案三：分布式一致性算法， raft, paxos。
     */
    public void electLeader(List<ServerMeta> nodeList) {
        List<ServerMeta> leaderNodes = nodeList.stream().filter(ServerMeta::isStatus).filter(ServerMeta::isLeader).toList();
        if (CollectionUtils.isEmpty(leaderNodes)) {
            log.warn(" ===>没有主节点，进行选主：{}", nodeList);
            doElect(nodeList);
        } else if (leaderNodes.size() > 1) {
            log.warn(" ===> 主节点数量大于1，进行选主:{}", nodeList);
            doElect(nodeList);
        } else {
            log.debug(" ===> 主节点正常，不需要选主");
        }
    }


    private void doElect(List<ServerMeta> nodeList) {
        ServerMeta candidate = null;

        for (ServerMeta node : nodeList) {
            node.setLeader(false);
            if (node.isStatus()) {
                if (candidate == null) {
                    candidate = node;
                } else {
                    // 选择最小的hashCode节点为主节点。
                    if (node.hashCode() <= candidate.hashCode()) {
                        candidate = node;
                    }
                }
            }
        }

        if (candidate == null) {
            log.warn(" ===> 选举失败，没有选出主节点：{}", nodeList);
        } else {
            candidate.setLeader(true);
            log.info(" ===> 选举成功，主节点为：{}", candidate);
        }
    }


}
